﻿#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <Windows.h>
using namespace std;

//throw：用于抛出异常。当程序执行到throw语句时，会立即停止当前函数的执行，并开始查找匹配的catch块。
//try：包含可能会抛出异常的代码块。try块中的代码会被监视，一旦抛出异常，控制流会跳转到对应的catch块。
//catch：用于捕获和处理异常。catch块会处理与其异常类型匹配的异常。

//执行流程：
//当try块中的代码抛出异常（通过throw），程序会立即退出try块，并在调用栈中查找匹配的catch块。
//如果找到匹配的catch块，则执行该catch块中的代码。
//如果没有找到匹配的catch块，程序会终止（可能会调用std::terminate）。
//如果异常被成功捕获并处理，程序会继续执行catch块之后的代码（而不是回到throw之后的代码）。

//class A {
//public:
//	A() { cout << "A()" << endl; }
//	~A() { cout << "~A()" << endl; }
//};
//
//double Division(int len, int time) {
//	if (time == 0) throw "除0错误";
//	else return (double)len / (double)time;
//}
//
//void Func() {
//	//A aa;//如果在这里定义，即使抛异常还是会调用析构
//	int len, time;
//	cin >> len >> time;
//	cout << Division(len, time) << endl;//如果抛异常，这行之后的语句都不会执行
//
//	A aa;//如果抛异常，不会创建aa
//}
//int main() {
//	try {
//		Func();
//	}
//	catch (const char* str) { //抛异常才执行catch
//		cout << str << endl;
//	}
//
//	return 0;
//}



//double Division(int len, int time) {
//	if (time == 0) throw "除0错误";
//	else return (double)len / (double)time;
//}
//
//void Func() {
//	//如果有多个类型匹配的异常捕获，走最近那个
//	try {
//		int len, time;
//		cin >> len >> time;
//		cout << Division(len, time) << endl;
//	}
//	catch (const char* s) {
//		cout << s << endl;
//	}
//
//	cout << "xxxxxxxxxxxxx" << endl;
//}
//
//int main() {
//	try {
//		Func();
//	}
//	catch (const char* str) {
//		cout << str << endl;
//	}
//
//	return 0;
//}



//double Division(int len, int time) {
//	if (time == 0) throw "除0错误";
//	else return (double)len / (double)time;
//}
//
//void f1() { throw 1; }
//void Func() {
//	try {
//		int len, time;
//		cin >> len >> time;
//		cout << Division(len, time) << endl;
//	}
//	catch (const char* s) {
//		cout << s << endl;
//	}
//	f1();
//}
//
//int main() {
//	while (1) {
//		try {
//			Func();
//		}
//		catch (const char* str) {
//			cout << str << endl;
//		}
//		catch (...) { //用于捕获没按规范(或约定)抛的异常
//			cout << "未知异常" << endl;
//		}
//	}
//
//	return 0;
//}



//4.自定义异常体系
//可以抛出的派生类对象，使用基类捕获，这个在实际中非常实用
//实际使用中很多公司都会自定义自己的异常体系进行规范的异常管理，
//因为一个项目中如果大家随意抛异常，那么外层的调用者基本就没办法玩了
// 服务器开发中通常使用的异常继承体系
class Exception {
public:
	Exception(const string& errmsg, int id)
		:_errmsg(errmsg)
		, _id(id) {
	}
	virtual string what() const { return _errmsg; }
protected:
	string _errmsg;//错误描述
	int _id;//错误编号
};
class SqlException : public Exception {
public:
	SqlException(const string& errmsg, int id, const string& sql)
		:Exception(errmsg, id)
		, _sql(sql) {
	}
	virtual string what() const {
		string str = "SqlException:";
		str += _errmsg;
		str += "->";
		str += _sql;
		return str;
	}
private:
	const string _sql;
};
class CacheException : public Exception {
public:
	CacheException(const string& errmsg, int id)
		:Exception(errmsg, id) {
	}
	virtual string what() const {
		string str = "CacheException:";
		str += _errmsg;
		return str;
	}
};
class HttpServerException : public Exception {
public:
	HttpServerException(const string& errmsg, int id, const string& type)
		:Exception(errmsg, id)
		, _type(type) {
	}
	virtual string what() const {
		string str = "HttpServerException:";
		str += _type;
		str += ":";
		str += _errmsg;
		return str;
	}
private:
	const string _type;
};
void SQLMgr() {
	srand((size_t)time(0));
	if (rand() % 7 == 0) throw SqlException("权限不足", 100, "select * from name = '张三'");
	//throw "xxxxxx";
}
void CacheMgr() {
	srand((size_t)time(0));
	if (rand() % 5 == 0) throw CacheException("权限不足", 100);
	else if (rand() % 6 == 0) throw CacheException("数据不存在", 101);
	SQLMgr();
}
void HttpServer() {
	// ...
	srand((size_t)time(0));
	if (rand() % 3 == 0) throw HttpServerException("请求资源不存在", 100, "get");
	else if (rand() % 4 == 0) throw HttpServerException("权限不足", 101, "post");
	CacheMgr();
}
//int main() {
//	while (1) {
//		Sleep(500);
//		try {
//			HttpServer();
//		}
//		catch (const Exception& e) // 这里捕获父类对象就可以
//		{
//			// 多态
//			cout << e.what() << endl;
//		}
//		catch (...) {
//			cout << "Unkown Exception" << endl;
//		}
//	}
//	return 0;
//}



//3.2 异常的重新抛出
//double Division(int a, int b) {
//	if (b == 0) throw "Division by zero condition!";
//	return (double)a / (double)b;
//}
//void Func() {
//	// 这里可以看到如果发生除0错误抛出异常，另外下面的array没有得到释放。
//	// 所以这里捕获异常后并不处理异常，异常还是交给外面处理，这里捕获了再重新抛出去。
//
//	//没有异常的情况：正常执行 Division 函数,执行完 try 块后，跳过 catch 块
//	//继续执行到函数末尾的 delete[] array，正常释放内存
//
//	//发生异常的情况：当 Division 抛出异常时，程序跳转到 catch 块
//	//在 catch 块中：先释放 array 内存（避免内存泄漏），然后通过 throw; 重新抛出相同的异常
//	//函数中 catch 块之后的代码（包括最后的 delete[]）不会被执行，异常被传递到 main 的 catch 块处理
//	int* array = new int[10];
//	try {
//		int len, time;
//		cin >> len >> time;
//		cout << Division(len, time) << endl;
//	}
//	////方式一
//	//catch (const char* errmsg) {
//	//	cout << "有异常释放：delete []" << array << endl;
//	//	delete[] array;
//	//	throw errmsg;
//	//}
//	//方式二：捕获什么抛什么
//	catch (...) {
//		cout << "有异常释放：delete []" << array << endl;
//		delete[] array;
//		throw;
//	}
//
//	cout << "无异常释放：delete []" << array << endl;
//	delete[] array;
//}
//int main() {
//	try {
//		Func();
//	}
//	catch (const char* errmsg) {
//		cout << errmsg << endl;
//	}
//	return 0;
//}



//1.如果 array1 的 new 抛异常（比如内存不足），array1 还未成功分配，
//程序会直接跳到 main 的 catch (const exception& e) 处理，因为 new 失败会抛出 std::bad_alloc（继承自 std::exception）。
//2.如果 array2 的 new 抛异常，此时 array1 已经分配成功，需要先释放 array1，再让异常传递到外层捕获。
//3.如果 new 了更多数组（比如 3 个），每个 new 都可能抛异常，需要确保之前成功分配的数组被正确释放，代码会变得冗长且容易出错。
//double Division(int a, int b) {
//	if (b == 0) throw "Division by zero condition!";
//	return (double)a / (double)b;
//}
//void Func() {
//	int* array1 = new int[10];
//	int* array2 = new int[20];
//	try {
//		int len, time;
//		cin >> len >> time;
//		cout << Division(len, time) << endl;
//	}
//	catch (...) {
//		cout << "有异常释放：delete []" << array1 << endl;
//		delete[] array1;
//		cout << "有异常释放：delete []" << array2 << endl;
//		delete[] array2;
//		throw;
//	}
//
//	cout << "无异常释放：delete []" << array1 << endl;
//	delete[] array1;
//
//	cout << "无异常释放：delete []" << array2 << endl;
//	delete[] array2;
//}
//int main() {
//	try {
//		Func();
//	}
//	catch (const char* errmsg) {
//		cout << errmsg << endl;
//	}
//	catch (const exception& e) {
//		cout << e.what() << endl;
//	}
//	return 0;
//}



//3.4 异常规范
//异常规格说明的目的是为了让函数使用者知道该函数可能抛出的异常有哪些。
//可以在函数的后面接throw(类型)，列出这个函数可能抛掷的所有异常类型。
//仅作为文档提示：
//它只是向程序员表明“这个函数可能会抛出某些类型的异常”，但编译器不会强制检查函数体内是否真的只抛出了这些异常。
//double Division(int a, int b) throw(const char*) {
//	if (b == 0) throw "Division by zero condition!";
//	return (double)a / (double)b;
//}
//void Func() throw(const char*) {
//	int len, time;
//	cin >> len >> time;
//	cout << Division(len, time) << endl;
//}
//int main() {
//	try {
//		Func();
//	}
//	catch (const char* errmsg) {
//		cout << errmsg << endl;
//	}
//	return 0;
//}

// C++11 中新增的noexcept，表示确定不会抛异常
//但加了noexcept 却抛异常就不捕获。throw()不会
//thread() noexcept;
//thread(thread&& x) noexcept;

